
package org.sidora.core;

import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.query.Predicate;
import java.util.List;
import java.util.TreeSet;
import org.sidora.core.context.Context;
import org.sidora.core.util.AbstractInventory;
import org.sidora.core.util.OCProvider;
import org.sidora.core.util.ParameterCollector;

/**
 * Document
 * @author Enric Tartera, Juan Manuel Gimeno, Roger Masgoret
 * @version 1.0
 */
public class Document implements Comparable, Describable{
    
    private KeyObject id;
    
    private Describable coleccio;
    
    public Category type;
    private String description;
    private String path;
    private String physicalPath;
    private Action action;
    private String name;
    
    /** Creates a new instance of Document */
    public Document() {
    }
    
    public KeyObject getId() {
        return id;
    }
    
    public void setId(KeyObject id) {
        this.id = id;
    }
    
    public Category getType() {
        return type;
    }
    
    public void setType(Category type) {
        this.type = type;
    }
    
    public String getDescription() {
        return description;
    }
    
    public void setDescription(String description) {
        this.description = description;
    }
    
    public String getPath() {
        return path;
    }
    
    public void setPath(String path) {
        this.path = path;
    }
    
    public String getPhysicalPath() {
        return physicalPath;
    }
    
    public void setPhysicalPath(String physicalPath) {
        this.physicalPath = physicalPath;
    }
    
    public Action getAction() {
        return action;
    }
    
    public void setAction(Action action) {
        this.action = action;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public Site getSite() {
        return id.getSite();
    }
    
    public void setSite(Site site) {
        this.id.setSite(site);
    }
    
    public Zone getZone() {
        return id.getZone();
    }
    public void setZone(Zone zone) {
        this.id.setZone(zone);
    }
    
    @Override
    public String toString() {
        if (name == null){
            return "New Doc" + id.getNumberString();
        }else{
            return name;
        }
    }
    
    
    //////////////////////////////////////////////////////////////////////////
    public static class Inventory extends AbstractInventory {
        
        public boolean exist(final KeyObject id) throws Exception{
            ObjectContainer db = OCProvider.getInstance();
            ObjectSet<Document> documents = db.query(new Predicate<Document>() {
                
                public boolean match(Document doc) {
                    return doc.id.equals(id);
                }
            });
            db.commit();
            if (documents.hasNext()){
                return true;
            } else {
                return false;
            }
        }
        
        @Override
        public Object getNewObject(ParameterCollector param) throws Exception {
            
            //Primer creem l'objecte segons el type
            Document document;
            //context = new Context();
            
            if(param.get("type")instanceof String){
                String type = (String) param.get("type");
                
                if (type.equals("Document")){
                    document = new Document();
                }else if (type.equals("Photo")){
                    document = new Photo();
                }else{
                    throw new RuntimeException("Type not found");
                }
            }else{
                throw new RuntimeException("Type not specified");
            }
            
            //Aconsgeguim el key object
            document.id = getNewKey(param);
            //En cas que es vulgui un altre identificador
            if (param.get("id")!=null){
                Integer num = (Integer) param.get("id");
                document.id.setNumber(num);
            }
            
            if (param.get("name")!=null){
                String str = (String) param.get("name");
                document.setName(str);
            }
            
            //Relacionem el Document amb l'objecte que el contindra.'
            if (param.get("object") != null){
                document.setColeccio((Describable)param.get("object"));
            }else{
                throw new RuntimeException();
            }
            
            return document;
        }
        
        @Override
        public Object getObject(ParameterCollector param) {
//		Carrega el Context amb el corresponent keyobject
            final KeyObject key = (KeyObject) param.get("id");
            ObjectContainer db = OCProvider.getInstance();
            
            ObjectSet <Document> ues = db.query(new Predicate <Document>() {
                public boolean match(Document doc) {
                    return (doc.id.equals(key));
                }
            });
            db.commit();
            
            if (ues.hasNext()){
                return ues.next();
            } else throw new RuntimeException("UE inexistent");
        }
        
        
        public static List getList() {
            ObjectContainer db = OCProvider.getInstance();
            List<Document> list = db.query(Document.class);
            db.commit();
            return list;
        }
        
        @Override
        public KeyObject getNewKey(ParameterCollector param) {
            
            final Zone zone = (Zone) param.get("zone");
            //se li dona el valor inicial per defecte
            KeyObject key = new KeyObject();
            key.setNumber(1);
            key.setSite(zone.getSite());
            key.setZone(zone);
            
            //es busca a la base d'objectes totes les inst�ncies de Context de la zona
            ObjectContainer db = OCProvider.getInstance();
            List<Document> documents = db.query(new Predicate <Document> (){
                @Override
                public boolean match(Document doc) {
                    return doc.id.getZone().equals(zone);
                }
            });
            //En cas que hi hagi d'altres contexts a la zona busca el nombre mes alt i en suma un
            if (documents.size()!= 0){
                TreeSet <Document> docs = new TreeSet<Document>(documents);
                Document document = docs.last();
                Integer integer = document.id.getNumber()+1;
                key.setNumber(integer);
                return key;
            }
            //En cas contrari pasa el valor per defecte
            else return key;
            
        }
        
        public static List<Document> getList(final Describable des) {
            
            if(des instanceof Site){
                return getList((Site)des);
            } else if(des instanceof Zone){
                return getList((Zone)des);
            } else if(des instanceof Feature){
                return getList((Feature)des);
            } else if(des instanceof Context){
                return getList((Context)des);
            }
            
            return null;
        }
        
        public static List<Document> getList(final Site site) {
            ObjectContainer db = OCProvider.getInstance();
            List<Document> list = db.query(new Predicate<Document>(){
                
                @Override
                public boolean match(Document document) {
                    // TODO Auto-generated method stub
                    return document.id.getSite()==site;
                }});
                db.commit();
                return list;
        }
        
        public static List<Document> getList(final Zone zone) {
            ObjectContainer db = OCProvider.getInstance();
            List<Document> list = db.query(new Predicate<Document>(){
                
                @Override
                public boolean match(Document document) {
                    // TODO Auto-generated method stub
                    return document.id.getZone()==zone;
                }});
                db.commit();
                return list;
        }
        
        public static List<Document> getList(final Sector sector) {
            ObjectContainer db = OCProvider.getInstance();
            List<Document> list = db.query(new Predicate<Document>(){
                
                @Override
                public boolean match(Document document) {
                    // TODO Auto-generated method stub
                    //return document.sectors.contains(sector);
                    return document.getColeccio() == sector;
                    //return document.getSectors().contains(sector);
                }});
                db.commit();
                return list;
        }
        
        public static List<Document> getList(final Feature feature) {
            ObjectContainer db = OCProvider.getInstance();
            List<Document> list = db.query(new Predicate<Document>(){
                
                @Override
                public boolean match(Document document) {
                    //TODO comprovar als testos unitaris que la comparaci� funcioni.
                    return document.getColeccio() == feature;
                    //return document.getFeature()==feature;
                }});
                //TODO mirar per que fem commit
                db.commit();
                return list;
        }
        
        
        public static List<Document> getList(final Context context) {
            ObjectContainer db = OCProvider.getInstance();
            List<Document> list = db.query(new Predicate<Document>(){
                
                @Override
                public boolean match(Document document) {
                    //TODO comprovar als testos unitaris que la comparaci� funcioni.
                    return document.getColeccio() == context;
                    //return document.getFeature()==feature;
                }});
                //TODO mirar per que fem commit
                db.commit();
                return list;
        }
        
        
    }
    
    public Describable getColeccio() {
        return coleccio;
    }
    
    public void setColeccio(Describable coleccio) {
        this.coleccio = coleccio;
    }
    
    public int compareTo(Object obj) {
        Document doc = (Document) obj;
        return this.getName().compareTo(doc.getName());
        //Context aue = (Context) obj;
        //return this.toString().compareTo(aue.toString());
        
    }    
    
}
